/*
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
 * MA  02110-1301, USA.
 *
 * http://www.gnu.org/copyleft/gpl.html
 */
package com.aionemu.gameserver.utils.mediator;

import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;

import javolution.util.FastList;
import javolution.util.FastMap;

import com.aionemu.gameserver.utils.mediator.IMediatorMember.eMediatorEvent;
import com.aionemu.gameserver.utils.mediator.IMediatorMember.eMediatorMemberType;
import com.aionemu.gameserver.utils.mediator.IMediatorMember.eRelationType;

/**
 * @author lyahim
 *
 */
public class Mediator
{
	private static final Map<Integer, IMediatorMember>	members			= new FastMap<Integer, IMediatorMember>().shared();
	private static final Map<Integer, Mediator>			relationship	= new FastMap<Integer, Mediator>().shared();

	/**
	 * Attach an object to mediator, if object already had relation with other, reload old relation data
	 * @param newMemb
	 * @return Mediator for object
	 */
	public static Mediator attach(IMediatorMember newMemb)
	{
		Mediator med = null;
		if (relationship.get(newMemb.getObjectId()) == null)
		{
			med = new Mediator(newMemb.getObjectId());
			relationship.put(newMemb.getObjectId(), med);
			members.put(newMemb.getObjectId(), newMemb);
		}
		else
		{
			med = relationship.get(newMemb.getObjectId());
			members.put(newMemb.getObjectId(), newMemb);
		}
		return med;
	}

	private final Map<Integer, eRelationType>	relations	= new FastMap<Integer, eRelationType>();
	private final Integer						member;

	Mediator(Integer member)
	{
		this.member = member;
	}

	/**
	 * Send Message all object what is in relation with sender
	 * @param event
	 */
	public void sendMessage(eMediatorEvent event)
	{
		for (Integer membs : relations.keySet())
		{
			if (members.get(membs) != null)
				members.get(membs).handle(event, members.get(member));
		}
	}

	public void removeMember()
	{
		sendMessage(eMediatorEvent.REMOVE);
		//		relationship.remove(member);
		members.remove(member);
	}

	/**
	 * Send Message all object what is in specified relation with sender
	 * @param event
	 */
	public void sendMessage(eRelationType relType, eMediatorEvent event)
	{
		for (Entry<Integer, eRelationType> membs : relations.entrySet())
			if (membs.getValue().equals(relType))
				if (members.get(membs.getKey()) != null && membs.getKey() != member)
					members.get(membs.getKey()).handle(event, members.get(member));
	}

	public void sendMessage(IMediatorMember memb, eMediatorEvent event)
	{
		sendMessage(memb, event);
	}

	public void sendMessage(IMediatorMember memb, eMediatorEvent event, Object... params)
	{
		if (relations.containsKey(memb.getObjectId()) && members.containsKey(memb.getObjectId()))
			members.get(memb.getObjectId()).handle(event, members.get(member), params);
	}

	public Map<Integer, eRelationType> getRelationShip()
	{
		return relations;
	}

	public Collection<IMediatorMember> getRelationShipByType(eRelationType type)
	{
		Collection<IMediatorMember> list = new FastList<IMediatorMember>();
		for (Entry<Integer, eRelationType> memb : relations.entrySet())
		{
			if (memb.getValue().equals(type))
			{
				if (members.containsKey(memb.getKey()))
					list.add(members.get(memb.getKey()));
			}
		}
		return list;
	}

	public FastList<IMediatorMember> getRelationShipByTypeAndMemberType(eRelationType type, eMediatorMemberType memberType)
	{
		FastList<IMediatorMember> list = FastList.newInstance();
		for (Entry<Integer, eRelationType> memb : relations.entrySet())
		{
			if (memb.getValue().equals(type))
			{
				if (members.containsKey(memb.getKey()))
				{
					IMediatorMember m = members.get(memb.getKey());
					if (m.getType().equals(memberType))
						list.add(members.get(memb.getKey()));
				}
			}
		}
		return list;
	}

	private boolean createRelationShip(IMediatorMember obj, eRelationType type)
	{
		if (relationship.get(obj.getObjectId()) != null)
		{
			relations.put(obj.getObjectId(), type);
			sendMessage(obj, eMediatorEvent.CREATE);
			return true;
		}
		return false;
	}

	/**
	 * get Relation between two objects
	 * @param obj
	 * @return null if obj not attached to Mediator
	 */
	public eRelationType getRelationBetweenObjects(IMediatorMember obj)
	{
		return relations.get(obj.getObjectId());
	}

	/**
	 * Set relationship between two objects, if relation not exist, create a new.
	 * If type is null, delete relation.
	 * @param obj
	 * @param type
	 * @return false if obj not attached to Mediator
	 */
	public boolean setRelationBetweenObjects(IMediatorMember obj, eRelationType Type)
	{
		if (Type == null)
		{
			relations.remove(obj.getObjectId());
			sendMessage(obj, eMediatorEvent.REMOVE);
			return true;
		}
		if (getRelationBetweenObjects(obj) == null)
			return createRelationShip(obj, Type);
		else
		{
			relations.remove(obj.getObjectId());
			relations.put(obj.getObjectId(), Type);
			sendMessage(obj, eMediatorEvent.CHANGERELATIONTYPE, Type);
			return true;
		}
	}
}
